home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 January: Mac OS SDK / Dev.CD Jan 98 SDK2.toast / Development Kits (Disc 2) / ScriptX / Code Samples / autofind / source / autofind.sx < prev    next >
Encoding:
Text File  |  1996-05-21  |  15.5 KB  |  546 lines  |  [TEXT/ttxt]

  1. ---<<<
  2. in module Autofinder
  3.  
  4. class AutoFinderTitle (TitleContainer)
  5. instance variables
  6.     dir            -- The directory of containers.
  7.     media
  8.     mouse        -- MouseDevice to change cursor to @Wait and @Arrow.
  9.     stage        -- The main full screen window of the title.
  10.     currentscene    -- The current scene in the stage
  11.     music        -- Music for intro
  12. --    intro
  13.     queryCriteria    -- Selections made by user
  14.     carDatabase        -- The database of classified ads for available cars.
  15.     modelDatabase    -- The database of model cars.
  16.     carsChosen        -- The result of searching database with queryCriteria.
  17.     modelsChosen    -- The model cars which represent the intro query.
  18.     buttons            -- list of currently visible buttons
  19.     grapherButton
  20.     mapButton
  21.     classifiedsButton
  22.     mainMenuButton
  23.     exitButton
  24.     actuator
  25. end
  26.  
  27. method afterinit self {class AutoFinderTitle} #rest args ->
  28. (
  29.     local media
  30.     
  31.     apply nextMethod self args
  32.  
  33.     self.mouse := new MouseDevice    
  34.     self.buttons := #()
  35.     self.queryCriteria := new KeyedLinkedList
  36.     self.currentScene := undefined
  37.     
  38.     media := open librarycontainer dir:(parentDir theScriptDir) \
  39.         path:"media.sxl"
  40.     
  41.     
  42.     local MainMenuButton := new navigationButton name:"MainMenu" \
  43.         releasedBitmap:media["Main Hilite"].bbox \
  44.         pressedBitmap:media["Main Hilite"]     
  45.     MainMenuButton.authordata := self
  46.     MainMenuButton.activateAction := (adata pb -> 
  47.                     addTimeCallback theEventTimeStampClock (autofind -> enterMainMenu autoFind) \
  48.                         adata #() theEventTimeStampClock.time true
  49.             )
  50.     self.mainMenuButton := mainMenuButton
  51.     
  52.     local MapButton := new navigationButton name:"Map" \
  53.         releasedBitmap:media["Map Hilite"].bbox \
  54.         pressedBitmap:media["Map Hilite"] 
  55.     MapButton.authordata := self    
  56.     MapButton.activateAction := (adata pb ->
  57.                     if (getClass adata.currentScene = AutofinderMenu) do 
  58.                     (
  59.                         local query := getQueryCriteria adata.currentScene
  60.                         executeQuery adata query
  61.                         adata.queryCriteria := query
  62.                     )
  63.                     addTimeCallback theEventTimeStampClock (autofind -> enterMap autoFind) \
  64.                         adata #() theEventTimeStampClock.time true
  65.             )     
  66.     self.mapButton := MapButton
  67.  
  68.     local GrapherButton := new navigationButton name:"Grapher" \
  69.         releasedBitmap:media["Graph Hilite"].bbox \
  70.         pressedBitmap:media["Graph Hilite"] 
  71.     GrapherButton.authordata := self    
  72.     GrapherButton.activateAction := (adata pb ->
  73.                     if (getClass adata.currentScene = AutofinderMenu) do 
  74.                     (
  75.                         local query    := getQueryCriteria adata.currentScene
  76.                         executeQuery adata query
  77.                         adata.queryCriteria := query
  78.                     )
  79.                     addTimeCallback theEventTimeStampClock (autofind -> enterGrapher autoFind) \
  80.                         adata #() theEventTimeStampClock.time true
  81.             )     
  82.     self.grapherButton := grapherButton
  83.     
  84.     local ClassifiedButton := new navigationButton name:"Classified" \
  85.         releasedBitmap:media["Class Hilite"].bbox \
  86.         pressedBitmap:media["Class Hilite"]
  87.     ClassifiedButton.authordata := self    
  88.     ClassifiedButton.activateAction := (adata pb ->
  89.                     if (getClass adata.currentScene = AutofinderMenu) do
  90.                     ( 
  91.                         local query := getQueryCriteria adata.currentScene
  92.                         executeQuery adata query
  93.                         adata.queryCriteria := query
  94.                     )
  95.                     addTimeCallback theEventTimeStampClock (autofind -> enterAds autoFind) \
  96.                         adata #() theEventTimeStampClock.time true
  97.             )     
  98.     self.classifiedsButton := classifiedButton    
  99.  
  100.     self.media := media
  101.     
  102.     self
  103. )
  104.     
  105. -- Method createStage hides the system menu bar, and creates the main window.
  106. method createStage self {class AutoFinderTitle} ->
  107. (
  108.     local mouse := self.mouse
  109.     mouse.pointerType := @Wait
  110.  
  111.     hide self.systemMenuBar
  112.     self.stage := new FullScreenWindow \
  113.         title:self fill:blackBrush \
  114.         boundary:(new rect x2:640 y2:480) \
  115.         centered:true \
  116.         borderFill:blackbrush
  117.     self.stage.clock.scale := 24
  118.  
  119.     -- If running from title container, use title container directory, else, parentDir.
  120.     if (self.directory <> undefined) then
  121.         self.dir := self.directory
  122.     else
  123.         self.dir := parentDir theScriptDir
  124.  
  125.     self.actuator := new ActuatorController space:self.stage wholeSpace:false
  126.     
  127.     show self.stage
  128.     self.mouse.pointerType := @Arrow
  129. )
  130.  
  131. -- Method changeScene removes the current scene from the stage, and adds the new scene.
  132. method changeScene self {class AutoFinderTitle} newScene ->
  133. (
  134.     endMusic self
  135.  
  136.     -- If the currentScene is the grapher, modify cars and models selected
  137.     if (getclass self.currentScene = AutoGrapher) do
  138.     (
  139.         local modelsSelected := self.currentScene.objectList
  140.         local modelList := for c in modelsSelected collect c.name
  141.         local function carMatch car dummy -> (isAKindOf car adDataObject) and \
  142.              (isMember modelList car.model)    
  143.          local carsSelected := chooseAll self.carsChosen carMatch undefined
  144.         self.modelsChosen := modelsSelected
  145.         self.carsChosen := carsSelected
  146.     )
  147.  
  148.     -- If the currentScene is the map, besure to close detail map window
  149.     if (getclass self.currentScene = Mapper) do
  150.     (
  151.         local map := self.currentscene
  152.         local detailDoc := map.detailDocument
  153.         if (NOT detailDoc == undefined) do 
  154.         (
  155.             local detailWin := detailDoc.presentedBy
  156.             if detailWin.isVisible do hide detailWin
  157.         )
  158.     )
  159.  
  160.     self.stage.compositor.enabled := false
  161.     -- Delete the current scene and make it purgeable.
  162.     if (self.currentScene <> undefined) do
  163.     (
  164.         -- Remove buttons from stage
  165.         emptyout self.actuator
  166.         for butn in self.buttons do deleteOne self.stage butn
  167.         emptyout self.buttons
  168.         
  169.         deleteOne self.stage self.currentScene
  170.         leaveScene self.currentScene
  171. --        if (canObjectDo self.currentScene purgeObject) do 
  172. --            purgeObject self.currentScene
  173.         self.currentScene := undefined
  174.     )
  175.     
  176.     -- Change to the new scene.
  177.     self.currentScene := newScene
  178.     prepend self.stage self.currentScene
  179.     self.stage.compositor.enabled := true
  180. )
  181.  
  182. -- Method start inits scenes, and plays the introduction.
  183. method start self {class AutoFinderTitle} ->
  184. (
  185.     -- should get moved to an init
  186.     initKeyboardWatch self
  187.  
  188.     -- Create carDB from carAd data
  189.     local carDB := new Array
  190.     local adLib := open LibraryContainer dir:self.dir path:"cars.sxl" \
  191.         mode:@readOnly
  192.     for i in adLib[@data] do 
  193.     (
  194.         local ad := new AdDataObject data:i
  195.         append carDB ad
  196.     )
  197.         
  198.     self.carDatabase := carDB
  199.     
  200.     -- Create modelDB from modelCar data
  201.     local modelDB := #()
  202.     local modelLib := open LibraryContainer dir:self.dir path:"models.sxl" \
  203.         mode:@readonly
  204.     for model in (modelLib[@data]) do
  205.     (
  206.         local objProperties    := model[2]
  207.         local obj := apply makeModelCar ModelCar objProperties
  208.         append modelDB obj
  209.     )
  210.     self.modelDatabase := modelDB
  211.         
  212.     enterMainMenu self
  213.  
  214.     -- Start Music
  215.     self.music :=  self.media["music"]
  216.     playMusic self
  217. )
  218.  
  219. method playMusic self {class AutoFinderTitle} ->
  220. (
  221.     if (self.music == undefined) do
  222.         return
  223.  
  224.     playPrepare self.music 1
  225.     play self.music
  226. )
  227.  
  228. method endMusic self {class AutoFinderTitle} -> 
  229. (
  230.     local seconds := 4
  231.     local c := new Clock scale:60
  232.     local duration := seconds * 60
  233.     local decibels := -20
  234.  
  235.     if (self.music == undefined) do
  236.         return
  237.  
  238.     -- Schedule a periodic callback to change the volume by the delta.
  239.     addPeriodicCallback c (dap delta -> dap.volume := dap.volume + delta) \
  240.         self.music #((decibels - self.music.volume) / duration) 1
  241.  
  242.     -- Schedule a time callback to stop the clock.
  243.     addTimeCallBack c (clk autofind dap ->
  244.         clk.rate := 0
  245.         stop dap
  246.         playUnprepare dap
  247.         makePurgeable dap
  248.         autofind.music := undefined
  249.         ) c #(self, self.music) duration true
  250.     c.rate := 1
  251. )
  252.  
  253. -- Method executeQuery searches ads database for cars that match selections
  254. -- made by user 
  255. method executeQuery self {class AutoFinderTitle} query ->
  256. (
  257.     -- Get selected car addObjects that match user criteria
  258.     local carPool := self.carDatabase
  259.     local matchedCars := chooseAll carPool (ad dummy -> \
  260.         (isAKindOf ad AdDataObject) and \
  261.         (isMember query[@classification] ad.classification)) undefined
  262.     carPool := matchedCars
  263.     
  264.     local matchedCars := chooseAll carPool (ad dummy -> \
  265.         (isAKindOf ad AdDataObject) and \
  266.         (isMember query[@year] ad.year)) undefined
  267.     carPool := matchedCars
  268.  
  269.     local matchedCars := chooseAll carPool (ad dummy -> \
  270.         (isAKindOf ad AdDataObject) and \
  271.         (isMember query[@price] ad.price)) undefined
  272.     
  273.     self.carsChosen := matchedCars
  274.  
  275.     -- Get selected modelCars that match user criteria
  276.     local modelList := for c in self.carsChosen collect c.model
  277.     local function modelCarMatch car dummy -> (isAKindOf car ModelCar) and \
  278.          (isMember modelList car.name)    
  279.      self.modelsChosen := chooseAll self.modelDatabase modelCarMatch undefined
  280. )
  281.  
  282. method enterMainMenu self {class AutoFinderTitle} ->
  283. (
  284.     -- Set mouse to busy state
  285.     local mouse := self.mouse
  286.     mouse.pointerType := @Wait
  287.  
  288.     -- Load MainMenu
  289.     local mainMenu := new AutofinderMenu boundary:(new rect x2:640 y2:480) \
  290.         media:self.media
  291.     
  292.     -- Change to mainMenu scene
  293.     changeScene self mainMenu
  294.  
  295.     -- Add next scene buttons
  296.     local buttonList := #()
  297.     
  298.     local button := self.grapherButton
  299.     button.x := 528; button.y := 31
  300.     prepend self.stage button
  301.     append buttonList button
  302.  
  303.     button := self.mapButton
  304.     button.x := 528; button.y := 203
  305.     prepend self.stage button
  306.     append buttonList button
  307.  
  308.     button := self.classifiedsButton
  309.     button.x := 525; button.y := 365
  310.     prepend self.stage button
  311.     append buttonList button
  312.  
  313.     -- create exit button
  314.     local exitButton := new navigationButton name:"Exit" \
  315.         releasedBitmap:self.media["Exit Hilite"].bbox \
  316.         pressedBitmap:self.media["Exit Hilite"]     
  317.     exitButton.x := 39; exitButton.y := 409
  318.     exitButton.authordata := self
  319.     exitButton.activateAction := (adata pb -> quit() )
  320.     self.exitButton := exitButton
  321.     prepend self.stage exitButton    
  322.     append buttonList exitButton
  323.  
  324.     self.buttons := buttonList
  325.     addMany self.actuator self.buttons
  326.     
  327.     mouse.pointerType := @Arrow
  328. )
  329.  
  330. method enterGrapher self {class AutoFinderTitle} ->
  331. (
  332.     -- Set mouse to busy state
  333.     self.mouse.pointerType := @Wait
  334.  
  335.     -- Init the grapher
  336.     local theGrapher := new AutoGrapher media:self.media 
  337.  
  338.     -- Change to grapher scene
  339.     changeScene self theGrapher
  340.  
  341.     -- Add next scene buttons
  342.     self.mainMenuButton.x := 83
  343.     self.mainMenuButton.y := 15
  344.     prepend self.stage self.mainMenuButton
  345.     append self.buttons self.mainMenuButton
  346.  
  347.     self.classifiedsButton.x := 155
  348.     self.classifiedsButton.y := 12
  349.     prepend self.stage self.classifiedsButton
  350.     append self.buttons self.classifiedsButton
  351.  
  352.     self.mapButton.x := 236
  353.     self.mapButton.y := 15
  354.     prepend self.stage self.mapButton
  355.     append self.buttons self.mapButton
  356.     addMany self.actuator self.buttons
  357.  
  358.     addObjectsToGraph theGrapher self.modelsChosen
  359.     graphObjects theGrapher self.modelsChosen
  360.  
  361.     self.mouse.pointerType := @Arrow
  362. )
  363.  
  364. method enterAds self {class AutoFinderTitle} ->
  365. (
  366.     self.mouse.pointerType := @Wait
  367.  
  368.     -- instantiate the classified ads document
  369.     local lib := open LibraryContainer dir:self.dir path:"cars.sxl" mode:@readOnly
  370.     load lib["adObject"]
  371.  
  372.     -- Create the document itself.
  373.     local classifieds := new ClassifiedAds media:self.media \
  374.                             adsPerPage:3 \
  375.                             target:(new array)\
  376.                             boundary:(new rect x2:640 y2:480) 
  377.  
  378.     changeScene self classifieds
  379.  
  380.     postads classifieds self.carsChosen
  381.  
  382.     -- Add next scene buttons
  383.     self.mainMenuButton.x := 83
  384.     self.mainMenuButton.y := 15
  385.     prepend self.stage self.mainMenuButton
  386.     append self.buttons self.mainMenuButton
  387.  
  388.     self.mapButton.x := 157
  389.     self.mapButton.y := 14
  390.     prepend self.stage self.mapButton
  391.     append self.buttons self.mapButton
  392.  
  393.     self.grapherButton.x := 235
  394.     self.grapherButton.y := 14
  395.     prepend self.stage self.grapherButton
  396.     append self.buttons self.grapherButton
  397.     addMany self.actuator self.buttons
  398.  
  399.     self.mouse.pointerType := @Arrow
  400.     self
  401. )
  402.  
  403. -- Creates the Mapper scene and adds it to the stage.
  404. method enterMap self {class AutoFinderTitle} ->
  405. (
  406.     -- Set mouse to busy state
  407.     self.mouse.pointerType := @Wait
  408.  
  409.     -- Create the Mapper and add it to the stage.
  410.     local map := new Mapper boundary:(new Rect x2:640 y2:480) \
  411.         manager:self media:self.media
  412.  
  413.     changeScene self map
  414.  
  415.     addManyObjects map self.carsChosen
  416.  
  417.     -- Add next scene buttons
  418.     local buttonList := #()
  419.     local button := self.mainMenuButton
  420.     button.x := 83; button.y := 15
  421.     prepend self.stage button
  422.     append buttonList button
  423.  
  424.     button := self.classifiedsButton
  425.     button.x := 155; button.y := 12
  426.     prepend self.stage button
  427.     append buttonList button
  428.     
  429.     button := self.grapherButton
  430.     button.x := 235; button.y := 14
  431.     prepend self.stage button
  432.     append buttonList button
  433.  
  434.     self.buttons := buttonList
  435.     addMany self.actuator self.buttons
  436.  
  437.     self.mouse.pointerType := @Arrow
  438. )
  439.  
  440. -- Method to check if an accessory is appropriate for this title.  It must
  441. -- answer the following questions:
  442. --
  443. --    @question1 --Do you want to add yourself to me?
  444. --    @question2 --Do you inherit from TwoDPresenter, i.e. can you be appended
  445. --                 to a window?
  446. method isAppropriateAccessory self {class AutoFinderTitle} acc ->
  447. (
  448.    local answer := false
  449.  
  450.    if (isDefined accessoryAnswersGetter) and \
  451.       (canObjectDo acc accessoryAnswersGetter) do
  452.       (
  453.           if ((getOne acc.accessoryAnswers @question1) = @yes) then
  454.         (
  455.          answer := true
  456.         )
  457.           else
  458.         (
  459.             if ((getOne acc.accessoryAnswers @question2) = @yes) do
  460.             (
  461.                 answer := true
  462.             )
  463.          )
  464.       )
  465.    return answer
  466. )
  467.  
  468. -- Overridden example method to get and add a generic accessory to a scene.
  469. --
  470. -- (Note: This will not work for the tape measure accessory because the tape
  471. --        measure requires two items to be appended to the current scene, the
  472. --        tape measure and its 'display' instance variable.  Also, the tape 
  473. --        measure requires that the method updateScale be called on it after 
  474. --        it has been appended to the current scene.  But that is too specific
  475. --        for this general addAccessory method.  That is why the tape measure
  476. --        takes care of adding itself to a title.  See the tape measure
  477. --        accessory container's startupAction IV defined in maketape.sx.
  478. method addAccessory self {class AutoFinderTitle} acc ->
  479. (
  480.    self.mouse.pointerType := @Wait
  481.  
  482.    if ((getOne acc.accessoryAnswers @question1) != @yes) do
  483.    (
  484.       local thisAcc := (getAccessories acc)[1]  --assume there is only one item
  485.        
  486.       -- You could put additional code in here to check the various 
  487.       -- answers in the accessoryAnswers IV of the AccessoryContainer,
  488.       -- and decide what to do with the accessory based on those answers.
  489.       --
  490.       -- I am going to get check to see if the accessory can do an addToTitle.
  491.       -- If it can't, then I'll check to see if it's a presenter, and add it
  492.       -- it myself.
  493.        
  494.       if (canObjectDo thisAcc addToTitle) then
  495.       (
  496.          addToTitle thisAcc pres:self.currentScene
  497.       )
  498.       else
  499.       (
  500.          if ((getOne acc.accessoryAnswers @question2) = @yes) do
  501.          (
  502.             prepend self.currentScene thisAcc
  503.          )
  504.       )
  505.    )
  506.  
  507.    self.mouse.pointerType := @Arrow
  508.  
  509.    nextMethod self acc
  510. )
  511.  
  512. -- Method importTool opens a file dialog to import the tape measure.
  513. method importTool self {class AutoFinderTitle} ->
  514. (
  515.     -- Open a file panel to import the tape measure.
  516.     local op := new OpenPanel
  517.     openFilePanel op
  518.     if (not op.validReply) do return
  519.     
  520.     -- Open the storage container and load the tape meaure accessory.
  521.     self.mouse.pointerType := @Wait
  522.     local fileName := op.filename[size op.fileName]
  523.     deleteLast op.fileName
  524.     local drep := spawn theRootDir op.fileName
  525.     local c := open AccessoryContainer dir:drep path:fileName
  526.     addAccessory self c
  527. )
  528.  
  529. -- Method initKeyboardWatch sets up an event receiver for keyboard events,
  530. -- restricting the key code to the character "i". When an "i" is keyed and the
  531. -- @command key modifier is active, the importTool method is invoked on the stage manager.
  532. method initKeyboardWatch self {class AutoFinderTitle} ->
  533. (
  534.     local kd
  535.     kd := new KeyboardDownEvent
  536.     kd.device := new KeyboardDevice
  537.     kd.eventReceiver := (arg interest ev ->
  538.         if (isMember ev.keyModifiers @control) do importTool self)
  539.     kd.maxKeyCode := 73
  540.     kd.minKeyCode := 73
  541.     addEventInterest  kd
  542. )
  543.  
  544. "Compiled autofind.sx"
  545. --->>>
  546.